package math.statistics.distribution;

/**
 *
 * Fully Tested: No
 * Fully Documented: Yes
 * Created: 11-Dec-2011
 * Last Updated: 13-Dec-2011
 *
 * @author Shimu Wu
 */
public class BinomialDistribution extends StatisticalDistribution {

    /** The total number of trials */
    private int n;

    /** The probability of success on each trial */
    private double p;

    /**
     * Instantiates a BinomialDistribution having the given number of trials
     * and the probability of success on each trial.
     * 
     * @param n the total number of trials
     * @param p the probability of success on each individual trial
     */
    public BinomialDistribution(int n, double p) {
        this.n = n;
    }

    /**
     * Returns the binomial coefficient. In this context, it can be
     * viewed as the number of possible ways to arrange k successes in n trials.
     * 
     * @param k the number of successes in the given number of trials
     * @return the number of possible ways to arrange k successes in n trials.
     */
    public int getBinomialCoefficient(int k) {
        // Takes advantage of symmetry
        if (k > n - k) {
            k = n - k;
        }

        // Uses the multiplicative formula
        int product = 1;
        for (int i = 1; i <= k; i++) {
            product *= n - (k - i);
            product /= i;
        }
        return product;
    }

    /**
     * Returns the probability that exactly k successes will occur in
     * n trials. The calculation assumes the result of each trial is
     * independent (unaffected by the result of any other trial) and the
     * probability of success in trial is the same.
     * 
     * @param k
     * @return the probability that exactly k successes will occur in n
     * trials.
     */
    public double getProbability(int k) {
        return getBinomialCoefficient(k)
                * Math.pow(p, k) * Math.pow(1 - p, n - k);
    }

    /**
     * Returns the mean (expected value) of this binomial distribution.
     * <p> mean = np </p>
     * 
     * @return the mean (expected value)
     */
    @Override
    public double getMean() {
        if (mean == null) {
            mean = n * p;
        }
        return mean;
    }

    /**
     * Returns the standard deviation of this binomial distribution.
     * <p> standard deviation = sqrt(np(1-p)) </p>
     * 
     * @return the standard deviation
     */
    @Override
    public double getStandardDeviation() {
        if (standardDeviation == null) {
            standardDeviation = Math.sqrt(n * p * (1 - p));
        }
        return standardDeviation;
    }
}
